<?php


namespace App\Task;


use App\Game\Conf\MainCmd;
use App\Game\Conf\SubCmd;
use App\Game\Core\Packet;
use App\Service\Hupai;
use App\Service\PaiXing;

class HuCardTask
{

    /**
     * 用户打牌逻辑处理
     * @param $user_room_data
     * @param $out_cards
     * @param $account
     * @param $fd
     * @throws \Exception
     */
    public function doHu($user_room_data, $out_cards, $account, $fd): void
    {
        $game_conf = config('game');
        $user_conf = config('user');
        $card = $out_cards['card'];
        $serv = server();
        $flag = true;
        $user_data = json_decode($user_room_data[$account], true);
        $my_card = json_decode($user_data['card'], true);
        $cards[] = $my_card;
        $peng = json_decode($user_data['peng'], true);
        $gang = json_decode($user_data['gang'], true);
        $room_color_key = sprintf($game_conf['user_room_color'], $out_cards['room_no']);
        $colors = redis()->get($room_color_key);
        $colorNum = $colors[$account];
        $checkNum = PaiXing::checkNum($cards);
        if (!$checkNum) {
            $msg = array('status' => 1, 'info' => '胡牌失败，当前手牌数量有误！');
            $flag = $this->gameHuCard($serv, $fd, $msg);
        }
        //校验定缺，没有定缺花色的牌才可以胡牌
        $checkColor = PaiXing::checkColor($cards, $colorNum);
        if (!$checkColor) {
            $msg = array('status' => 2, 'info' => '胡牌失败，当前手牌中有定缺牌！');
            $flag = $this->gameHuCard($serv, $fd, $msg);
        }
        //计算胡牌
        $hu = (new Hupai())->start($my_card, $peng, $gang);
        if (empty($hu)) {
            $msg = array('status' => 3, 'info' => '炸胡');
            $flag = $this->gameHuCard($serv, $fd, $msg);
        }
        //校验牌型
        $result = PaiXing::checkPaiXing($hu, $peng, $gang);
        if (!is_array($result)) {
            $msg = array('status' => 4, 'info' => $result);
            $flag = $this->gameHuCard($serv, $fd, $msg);
        }
        $result['chair_id'] = $out_cards['chair_id'];
        $result['card'] = $card;
        if ($flag) {
            //更新积分
            $this->setScore($user_room_data, $result['points'], $account);
            $fds = $this->getUsers($user_room_data['uinfo'], $game_conf);// 房间玩家链接
            $this->gameHuCardResp($serv, $fds, $result);
        }
    }

    /**
     * 返回玩家房间桌位号
     * @param $room_no
     * @param $account
     * @return mixed
     */
    protected function findChairId($room_no, $account)
    {
        $game_conf = $this->game_conf;
        $room_chair_key = sprintf($game_conf['user_room_chair'], $room_no);
        $chair_data = json_decode(redis()->get($room_chair_key), true);
        return $chair_data[$account];
    }

    /**
     * 向客户端当前玩家发送错误提示响应, 单发
     * @param $serv
     * @param $fd
     * @param $param
     * @return bool
     */
    protected function gameHuCard($serv, $fd, $param)
    {
        $data = Packet::packFormat('OK', 1, $param);
        $data = Packet::packEncode($data, MainCmd::CMD_SYS, SubCmd::SUB_GAME_GANG_CARD_RESP);
        $serv->push($fd, $data, WEBSOCKET_OPCODE_BINARY);
        return false;
    }


    /**
     * 设置积分
     * @param $user_room_data
     * @param $cards
     * @param $account
     * @return mixed
     */
    protected function setScore($user_room_data, $score, $account)
    {
        //根据椅子查询手牌信息
        $uinfo_arr = $user_room_data['uinfo'];
        $uinfo_arr[$account]['score'] += $score;
        foreach ($uinfo_arr as $k => $v) {
            if ($k != $account) {
                $uinfo_arr[$v]['score'] -= $score;
            }
        }
        $param['uinfo'] = json_encode($uinfo_arr);
        //写会redis
        $this->updateRoomData($user_room_data['room_no'], $param);
    }


    /**
     * 批量更新房间数据
     * @param $room_no
     * @param $params
     */
    protected function updateRoomData($room_no, $params)
    {
        $game_conf = config('game');
        $room_data_key = sprintf($game_conf['user_room_data'], $room_no);
        if (redis()->exists($room_data_key)) {
            foreach ($params as $key => $val) {
                redis()->hSet($room_data_key, (string)$key, $val);
            }
        }
    }


    /**
     * 向客户端广播下家出牌响应, 群发
     * @param $serv
     * @param $fds
     * @param $param
     */
    protected function gameHuCardResp($serv, $fds, $param)
    {
        $data = Packet::packFormat('OK', 0, $param);
        $data = Packet::packEncode($data, MainCmd::CMD_SYS, SubCmd::SUB_GAME_HU_CARD_RESP);
        $this->pushToUsers($serv, $fds, $data);
    }

    /**
     * 对多用发送信息
     * @param $serv
     * @param $users
     * @param $data
     */
    protected function pushToUsers($serv, $users, $data)
    {
        foreach ($users as $fd) {
            //获取客户端信息
            $client_info = $serv->getClientInfo($fd);
            $client[$fd] = $client_info;
            if (isset($client_info['websocket_status']) && $client_info['websocket_status'] == 3) {
                $serv->push($fd, $data, WEBSOCKET_OPCODE_BINARY);
            }
        }
    }

    /**
     * 取出房间所有用户
     * @param $user_info
     * @param $game_conf
     * @return array
     */
    protected function getUsers($user_info, $game_conf)
    {
        $users = [];
        $uinfo = json_decode($user_info, true);
        foreach ($uinfo as $k => $v) {
            $user_bind_key = sprintf($game_conf['user_bind_key'], $k);
            $users[] = redis()->get($user_bind_key);
        }
        return $users;
    }

}